package com.zzh.tools.utils;


import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class ToolEntityAssignment {
    private static final String TAG = ToolEntityAssignment.class.getSimpleName();


    public static <T> T createBean(Class<T> cls) {
        if (cls == null) return null;
        T basicDirectValue = basicDirectAssignment(cls);
        if (basicDirectValue != null) {
            return basicDirectValue;
        }
        T bean = null;
        try {
            bean = cls.newInstance();
            Field[] fileds = cls.getDeclaredFields();
            for (Field field : fileds) {
                if (Modifier.isFinal(field.getModifiers())) {
                    continue;
                }
                if (Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                field.setAccessible(true);
                Class typeCls = field.getType();
                boolean isBasicStatus = basicAssignment(typeCls, field, bean);
                if (isBasicStatus) {
                    continue;
                }
                if (typeCls == List.class || typeCls == ArrayList.class) {
                    System.out.println("list");
                    Type type = field.getGenericType();
                    if (type instanceof ParameterizedType) {
                        ParameterizedType parameterizedType = (ParameterizedType) type;
                        Type[] values = parameterizedType.getActualTypeArguments();
                        ArrayList<Object> list = new ArrayList<>();
                        if (values != null && values.length >= 1) {
                            String paradigm = values[0].getTypeName();
                            Class paradigmClass = Class.forName(paradigm);
                            for (int i = 0; i < 3; i++) {
                                list.add(createBean(paradigmClass));
                            }
                        }
                        field.set(bean, list);
                    }
                } else if (typeCls == Map.class || typeCls == HashMap.class) {
                    System.out.println("hashmap");
                    Type type = field.getGenericType();
                    if (type instanceof ParameterizedType) {
                        ParameterizedType parameterizedType = (ParameterizedType) type;
                        Type[] values = parameterizedType.getActualTypeArguments();
                        HashMap<Object, Object> map = new HashMap<>();
                        if (values != null && values.length >= 2) {
                            String paradigmKey = values[0].getTypeName();
                            String paradigmValue = values[1].getTypeName();
                            Class paradigmKeyClass = Class.forName(paradigmKey);
                            Class paradigmValueClass = Class.forName(paradigmValue);
                            for (int i = 0; i < 3; i++) {
                                map.put(createBean(paradigmKeyClass), createBean(paradigmValueClass));
                            }
                        }
                        field.set(bean, map);
                    }
                } else if (typeCls == LinkedList.class) {
                    System.out.println("linkedlist");
                    Type type = field.getGenericType();
                    if (type instanceof ParameterizedType) {
                        ParameterizedType parameterizedType = (ParameterizedType) type;
                        Type[] values = parameterizedType.getActualTypeArguments();
                        LinkedList<Object> list = new LinkedList<>();
                        if (values != null && values.length >= 1) {
                            String paradigm = values[0].getTypeName();
                            Class paradigmClass = Class.forName(paradigm);
                            for (int i = 0; i < 3; i++) {
                                list.add(createBean(paradigmClass));
                            }
                        }
                        field.set(bean, list);
                    }
                } else {
                    createBean(typeCls);
                    System.out.println("other> " + typeCls.getName());
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return bean;
    }

    private static <T> T basicDirectAssignment(Class<T> typeCls) {
        if (typeCls == String.class) {
            return (T) randomString();
        } else if (typeCls == boolean.class || typeCls == Boolean.class) {
            return (T) randomBoolean();
        } else if (typeCls == int.class || typeCls == Integer.class) {
            return (T) randomInt();
        } else if (typeCls == long.class || typeCls == Long.class) {
            return (T) randomLong();
        } else if (typeCls == double.class || typeCls == Double.class) {
            return (T) randomDouble();
        } else if (typeCls == float.class || typeCls == Float.class) {
            return (T) randomFloat();
        } else if (typeCls == short.class || typeCls == Short.class) {
            return (T) randomShort();
        } else {
            return null;
        }
    }

    private static Short randomShort() {
        return 1;
    }

    private static Float randomFloat() {
        return Math.abs(new Random().nextFloat());
    }

    private static Double randomDouble() {
        return Math.abs(new Random().nextDouble());
    }

    private static Long randomLong() {
        return Math.abs(new Random().nextLong());
    }

    private static Integer randomInt() {
        return Math.abs(new Random().nextInt());
    }

    private static Boolean randomBoolean() {
        return new Random().nextBoolean();
    }

    private static String randomString() {
        return getRandomWord() + getRandomWord() + getRandomWord();
    }

    private static String getRandomWord() {
        String str = "zzh";
        int heightPos;
        int lowPos;
        Random rd = new Random();
        heightPos = 176 + Math.abs(rd.nextInt(39));
        lowPos = 161 + Math.abs(rd.nextInt(93));
        byte[] bt = new byte[2];
        bt[0] = Integer.valueOf(heightPos).byteValue();
        bt[1] = Integer.valueOf(lowPos).byteValue();
        try {
            str = new String(bt, "GBK");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return str;
    }

    private static <T> Boolean basicAssignment(Class typeCls, Field field, T bean) {
        boolean isStatus = false;
        try {
            if (typeCls == String.class) {
                field.set(bean, randomString());
                isStatus = true;
            } else if (typeCls == boolean.class || typeCls == Boolean.class) {
                field.set(bean, randomBoolean());
                isStatus = true;
            } else if (typeCls == int.class || typeCls == Integer.class) {
                field.set(bean, randomInt());
                isStatus = true;
            } else if (typeCls == long.class || typeCls == Long.class) {
                field.set(bean, randomLong());
                isStatus = true;
            } else if (typeCls == double.class || typeCls == Double.class) {
                field.set(bean, randomDouble());
                isStatus = true;
            } else if (typeCls == float.class || typeCls == Float.class) {
                field.set(bean, randomFloat());
                isStatus = true;
            } else if (typeCls == short.class || typeCls == Short.class) {
                field.set(bean, randomShort());
                isStatus = true;
            } else {
                System.out.println("other = " + typeCls.getName());
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return isStatus;
    }


    private static <T> List<T> createBeans(Class<T> cls, int count) {
        List<T> list = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            list.add(createBean(cls));
        }
        return list;
    }

    public static <T extends Object> List<? extends T> createBeans(int count, Class<? extends T>... cls) {
        if (cls == null) {
            return null;
        }
        if (cls.length == 1) {
            return createBeans(cls[0], count);
        }
        List<T> objects = new ArrayList<>();
        int tCount = cls.length;
        for (int i = 0; i < count; i++) {
            int index = (int) (1 + Math.random() * (tCount - 1 + 1)) - 1;
            objects.add(createBean(cls[index]));
        }
        return objects;
    }


}
